﻿using System;
using System.Collections.Generic;
using System.Text;
using System.CodeDom;
using System.Collections;

namespace _0512063_0512082
{
    class CodeAnalyser
    {
        #region Analyze function

        /// <summary>
        /// Tạo hàm nhập cho các tham số
        /// </summary>
        /// <returns></returns>
        public static CodeMemberMethod getInputMethod(CodeMemberMethod mainMethod, String methodname)
        {

            CodeMemberMethod inputfunction = new CodeMemberMethod();
            // public void xxx ()
            inputfunction.Attributes = MemberAttributes.Public | MemberAttributes.Final;
            inputfunction.Name = methodname;            
            // lấy danh sách các tham số cần nhập
            for (int i = 0; i < mainMethod.Parameters.Count; i++)
            {
                CodeParameterDeclarationExpression p = mainMethod.Parameters[i];
                // Nếu không phải kiểu mảng
                if (p.Type.ArrayRank == 0)
                {
                    inputfunction.Statements.Add(getInstruction("Nhap gia tri tham so " + p.Name + ": "));
                    CodeAssignStatement cas = new CodeAssignStatement();
                    cas.Left = new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), p.Name);
                    cas.Right = getParser(p.Type.BaseType);
                    inputfunction.Statements.Add(cas);
                }
                else if (p.Type.ArrayRank == 1)
                {
                    // yêu cầu nhập độ dài mảng
                    inputfunction.Statements.Add(getInstruction("Nhap do dai cua mang " + p.Name + ": "));
                    CodeVariableDeclarationStatement temp = new CodeVariableDeclarationStatement();
                    temp.Type = new CodeTypeReference("Int32");
                    temp.Name = "len_" + p.Name;
                    temp.InitExpression = getParser("Int32");
                    //inputfunction.Statements.Add(temp);--> bỏ vào trong khởi tạo mảng
                    
                    // Khởi tạo mảng
                    inputfunction.Statements.Add(InitArrayObject(p.Type, p.Name,temp));
                    // Nhập giá trị cho mảng
                    inputfunction.Statements.Add(inputArray(p.Type, p.Name, "i"));

                }
            }
            return inputfunction;
        }

        public static CodeMethodInvokeExpression getParser(String type)
        {
            CodeTypeReferenceExpression csSystemConsoleType =
                    new CodeTypeReferenceExpression("System.Console");
            CodeMethodReferenceExpression parser = new CodeMethodReferenceExpression();
            parser.TargetObject = new CodeVariableReferenceExpression(type);
            parser.MethodName = "Parse";
            CodeMethodInvokeExpression invokeParse = new CodeMethodInvokeExpression();
            invokeParse.Method = parser;
            invokeParse.Parameters.Add(new CodeMethodInvokeExpression(csSystemConsoleType, "ReadLine"));
            return invokeParse;
        }

        public static CodeMethodInvokeExpression pauseApplication()
        {
            // Create a type reference for the System.Console class.
            CodeTypeReferenceExpression csSystemConsoleType =
                new CodeTypeReferenceExpression("System.Console");
            // Build a Console.WriteLine statement.
            CodeMethodInvokeExpression cs1 = new CodeMethodInvokeExpression(
                csSystemConsoleType, "ReadLine");
            return cs1;
        }

        public static CodeMethodInvokeExpression getInstruction(String instr)
        {
            // Create a type reference for the System.Console class.
            CodeTypeReferenceExpression csSystemConsoleType =
                new CodeTypeReferenceExpression("System.Console");
            // Build a Console.WriteLine statement.
            CodeMethodInvokeExpression cs1 = new CodeMethodInvokeExpression(
                csSystemConsoleType, "WriteLine",
                new CodePrimitiveExpression(instr));
            return cs1;
        }

        /// <summary>
        /// phát sinh hàm kiểm tra
        /// </summary>
        /// <param name="mainMethod"></param>
        /// <returns></returns>
        public static CodeMemberMethod getCheckFunction(CodeMemberMethod mainMethod, String name)
        {
            CodeMemberMethod checkFunc = new CodeMemberMethod();
            checkFunc.Name = name;
            checkFunc.Attributes = MemberAttributes.Public | MemberAttributes.Final;
            checkFunc.ReturnType = new CodeTypeReference("Boolean");
                CodeConditionStatement con = (CodeConditionStatement)mainMethod.Statements[0];
                CodeVariableDeclarationStatement cvds = new CodeVariableDeclarationStatement();
                cvds.Type = new CodeTypeReference("Boolean");
                cvds.Name = "checker";
                cvds.InitExpression = con.Condition;
                checkFunc.Statements.Add(cvds);
                checkFunc.Statements.Add(new CodeSnippetExpression("return checker"));
            
            return checkFunc;
        }

        /// <summary>
        /// tạo hàm xuất
        /// </summary>
        /// <param name="mainMethod"></param>
        /// <param name="methodname"></param>
        /// <returns></returns>
        public static CodeMemberMethod getOutputMethod(CodeMemberMethod mainMethod, String methodname)
        {
            // chua kiem tra kieu mang

            CodeMemberMethod outputfunction = new CodeMemberMethod();
            outputfunction.Attributes = MemberAttributes.Public | MemberAttributes.Final;
            outputfunction.Name = methodname;
            CodeTypeReferenceExpression csSystemConsoleType =  new CodeTypeReferenceExpression("System.Console");

            
            CodeVariableDeclarationStatement v = (CodeVariableDeclarationStatement)mainMethod.Statements[1];
            
            // Nếu kết quả trả về ko phải mảng
            if (v.Type.ArrayRank == 0)
            {
                // Build a Console.WriteLine statement.
                CodeMethodInvokeExpression cs1 = new CodeMethodInvokeExpression(
                    csSystemConsoleType, "WriteLine",
                    new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), v.Name)
                    );
                outputfunction.Statements.Add(cs1);
            }
            else if (v.Type.ArrayRank == 1) // kết quả trả về là mảng
            {
                outputfunction.Statements.Add(outputArray(v.Type, v.Name, "i"));
            }
            return outputfunction;
        }
        
        /// <summary>
        /// Hàm tạo các biến thuộc tính cho lớp
        /// </summary>
        /// <param name="mainMethod"></param>
        /// <returns></returns>
        public static CodeMemberField[] getAllMemberFields(CodeMemberMethod mainMethod)
        {

            CodeMemberField[] collect = new CodeMemberField[mainMethod.Parameters.Count + 1];
            int i = 0;
            for (; i < mainMethod.Parameters.Count; i++)
            {
                CodeParameterDeclarationExpression p = mainMethod.Parameters[i];
                CodeMemberField cmf = new CodeMemberField();
                cmf.Type = p.Type;
                cmf.Name = p.Name.ToLower();
                cmf.Attributes = MemberAttributes.Private;
                collect[i] = cmf;
            }


            CodeVariableDeclarationStatement v = (CodeVariableDeclarationStatement)mainMethod.Statements[1];            
            CodeMemberField kq = new CodeMemberField(v.Type, v.Name);
            kq.Attributes = MemberAttributes.Private;
            collect[i] = kq;     

            return collect;
        }

        public static CodeMemberProperty[] getAllProperties(CodeMemberMethod mainMethod)
        {
            CodeMemberProperty[] collect = new CodeMemberProperty[mainMethod.Parameters.Count];
            for (int i = 0; i < mainMethod.Parameters.Count; i++)
            {
                CodeParameterDeclarationExpression p = mainMethod.Parameters[i];
                CodeMemberProperty cmp = new CodeMemberProperty();
                cmp.Attributes = MemberAttributes.Public | MemberAttributes.Final;
                cmp.Type = p.Type;
                cmp.Name = "Property"+p.Name.ToUpper();
                cmp.HasGet = true;
                cmp.GetStatements.Add(new CodeSnippetExpression("return " + p.Name));
                cmp.HasSet = true;
                cmp.SetStatements.Add(new CodeSnippetExpression(p.Name + " = value"));
                collect[i] = cmp;
            }
            return collect;
        }
                
        /// <summary>        
        /// tạo contructor của lớp
        /// </summary>
        /// <returns></returns>
        public static CodeConstructor getConstrutor()
        {
            CodeConstructor cons = new CodeConstructor();
            cons.Attributes = MemberAttributes.Public;
            //CodeAssignStatement cas = new CodeAssignStatement();
            //cas.Left = new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), "kq");
            //cas.Right = new CodePrimitiveExpression(0);
            //cons.Statements.Add(cas);
            return cons;
        }

        public static CodeCommentStatement getComment(String commenttext)
        {
            return new CodeCommentStatement(new CodeComment(commenttext, true));
        }

        public static CodeMemberMethod getProcess(CodeMemberMethod mainMethod, String methodname)
        {
            CodeMemberMethod method = new CodeMemberMethod();
            method.Name = methodname;
            method.Attributes = MemberAttributes.Final | MemberAttributes.Public;
            ArrayList statecopy = new ArrayList();

            for (int i = 2; i < mainMethod.Statements.Count - 1; i++ )
            {
                
                statecopy.Add(mainMethod.Statements[i]);
            }

            foreach (CodeStatement c in statecopy)
            {
                method.Statements.Add(c);
            }
            return method;
        }
        #endregion

        #region "Code util"

        /// <summary>
        /// Khai báo đối tượng
        /// </summary>
        /// <param name="type"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        public static CodeVariableDeclarationStatement
            DeclareVariable(String type, String name)
        {
            CodeTypeReference ctr = new CodeTypeReference(type);
            CodeVariableDeclarationStatement rs = new CodeVariableDeclarationStatement(ctr, name);
            CodeObjectCreateExpression newObj = new CodeObjectCreateExpression();
            newObj.CreateType = ctr;
            rs.InitExpression = newObj;
            return rs;
        }

        /// <summary>
        /// Tạo biểu thức thực thi một phương thức của một đối tượng
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        public static CodeMethodInvokeExpression
            InvokeOperation(String obj, String name)
        {
            CodeMethodReferenceExpression operation = new CodeMethodReferenceExpression();
            operation.TargetObject = new CodeVariableReferenceExpression(obj);
            operation.MethodName = name;
            CodeMethodInvokeExpression invoker = new CodeMethodInvokeExpression();
            invoker.Method = operation;
            return invoker;
        }


        /// <summary>
        /// Khởi tạo mảng
        /// </summary>
        /// <param name="type"></param>
        /// <param name="arrname"></param>
        /// <param name="len"></param>
        /// <returns></returns>
        public static CodeAssignStatement InitArrayObject(CodeTypeReference type, String arrname, CodeVariableDeclarationStatement len)
        {
            CodeAssignStatement cas = new CodeAssignStatement();
            cas.Left = new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), arrname);
            
            CodeArrayCreateExpression ca1 = new CodeArrayCreateExpression(type, len.InitExpression);

            cas.Right = ca1;
            return cas;
        }


        /// <summary>
        /// tạo vòng lặp nhập mảng
        /// </summary>
        /// <param name="TypeArray"></param>
        /// <param name="len"></param>
        /// <param name="loop"></param>
        /// <returns></returns>
        public static CodeIterationStatement inputArray(CodeTypeReference type, String arrary_name, String loopvar)
        {
            CodeVariableDeclarationStatement Declacration = new CodeVariableDeclarationStatement(new CodeTypeReference("Int32"), loopvar);
            Declacration.InitExpression = new CodePrimitiveExpression(0);
            CodeIterationStatement forloop = new CodeIterationStatement();
            forloop.InitStatement = Declacration;

            CodeAssignStatement assignment = new CodeAssignStatement(
            new CodeVariableReferenceExpression(loopvar),
            new CodeSnippetExpression(loopvar + " + 1"));

            forloop.IncrementStatement = assignment;
            forloop.TestExpression = new CodeSnippetExpression(loopvar + " < "+arrary_name+".Length");

            CodeArrayIndexerExpression index = new CodeArrayIndexerExpression();
            index.Indices.Add(new CodeVariableReferenceExpression(loopvar));
            index.TargetObject = new CodeSnippetExpression(arrary_name);

            // chạy hàm nhập
            CodeAssignStatement cas = new CodeAssignStatement();
            cas.Left = index;
            cas.Right = getParser(type.BaseType);
            forloop.Statements.Add(cas);
            return forloop;
        }

        /// <summary>
        /// tạo vòng lặp xuất mảng
        /// </summary>
        /// <param name="TypeArray"></param>
        /// <param name="len"></param>
        /// <param name="loop"></param>
        /// <returns></returns>
        public static CodeIterationStatement outputArray(CodeTypeReference type, String arrary_name, String loopvar)
        {
            CodeVariableDeclarationStatement Declacration = new CodeVariableDeclarationStatement(new CodeTypeReference("Int32"), loopvar);
            Declacration.InitExpression = new CodePrimitiveExpression(0);
            CodeIterationStatement forloop = new CodeIterationStatement();
            forloop.InitStatement = Declacration;

            CodeAssignStatement assignment = new CodeAssignStatement(
            new CodeVariableReferenceExpression(loopvar),
            new CodeSnippetExpression(loopvar + " + 1"));

            forloop.IncrementStatement = assignment;
            forloop.TestExpression = new CodeSnippetExpression(loopvar + " < " + arrary_name + ".Length");

            CodeArrayIndexerExpression index = new CodeArrayIndexerExpression();
            index.Indices.Add(new CodeVariableReferenceExpression(loopvar));
            index.TargetObject = new CodeSnippetExpression(arrary_name);

            // chạy hàm xuất
            // Create a type reference for the System.Console class.
            CodeTypeReferenceExpression csSystemConsoleType =
                new CodeTypeReferenceExpression("System.Console");
            // Build a Console.WriteLine statement.
            CodeMethodInvokeExpression cs1 = new CodeMethodInvokeExpression(
                csSystemConsoleType, "WriteLine",
                index);
            forloop.Statements.Add(cs1);
            return forloop;
        }

        #endregion
    }
}
